package com.manlitech.manlichat.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * SSL 证书工具
 * @author Shensg
 */
@Slf4j
public class SslUtil {

    private static volatile SSLContext sslContext = null;


    // type是PKCS12、path是pfx文件路径、password是pfx对应的密码
    public static SSLContext createSSLContext(String type ,String path ,String password) throws Exception {
        if(null == sslContext){
            synchronized (SslUtil.class) {
                if(null == sslContext){
                    // 支持JKS、PKCS12（我们项目中用的是阿里云免费申请的证书，下载tomcat解压后的pfx文件，对应PKCS12）
                    KeyStore ks = KeyStore.getInstance(type);
                    // 证书存放地址
                    InputStream ksInputStream = new FileInputStream(path);
                    ks.load(ksInputStream, password.toCharArray());
                    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    kmf.init(ks, password.toCharArray());
                    sslContext = SSLContext.getInstance("TLS");
                    //参数一：认证的密钥      参数二：对等信任认证  参数三：伪随机数生成器 。 由于单向认证，服务端不用验证客户端，所以第二个参数为null
                    sslContext.init(kmf.getKeyManagers(), null, null);
                }
            }
        }
        return sslContext;
    }

    public static TrustManager[] trustAllCerts() {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[]{};
            }

            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // TODO Auto-generated method stub
                return;
            }

            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // TODO Auto-generated method stub
                return;
            }
        }};

        return trustAllCerts;
    }

    /**
     *
     * 以下用于http请求配合使用
     *
     */

    private static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[1];
        TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements TrustManager,X509TrustManager {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
        public boolean isServerTrusted(X509Certificate[] certs) {
            return true;
        }
        public boolean isClientTrusted(X509Certificate[] certs) {
            return true;
        }
        @Override
        public void checkServerTrusted(X509Certificate[] certs, String authType)
                throws CertificateException {
            return;
        }
        @Override
        public void checkClientTrusted(X509Certificate[] certs, String authType)
                throws CertificateException {
            return;
        }
    }
    /**
     * 忽略HTTPS请求的SSL证书，必须在openConnection之前调用
     * @throws Exception
     */
    public static void ignoreSsl() throws Exception{
        HostnameVerifier hv = new HostnameVerifier() {
            @Override
            public boolean verify(String urlHostName, SSLSession session) {
                System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
                return true;
            }
        };
        trustAllHttpsCertificates();
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    /**
     * 在服务端单项的时候
     * 信任所有证书发送请求
     * @param getUrl
     * @return
     * @throws Exception
     */

    public static String httpsGet(String getUrl) throws Exception{
        HttpsURLConnection httpURLConnection = null;
        try {
            // 1. 得到访问地址的URL
            URL url = new URL(getUrl);
            if("https".equalsIgnoreCase(url.getProtocol())){
                SslUtil.ignoreSsl();
            }
            // 2. 得到网络访问对象java.net.HttpURLConnection
            httpURLConnection = (HttpsURLConnection) url.openConnection();
            /* 3. 设置请求参数（过期时间，输入、输出流、访问方式），以流的形式进行连接 */
            // 设置是否向HttpURLConnection输出
            httpURLConnection.setDoOutput(false);
            // 设置是否从httpUrlConnection读入
            httpURLConnection.setDoInput(true);
            // 设置请求方式　默认为GET
            httpURLConnection.setRequestMethod("GET");
            // 设置是否使用缓存
            httpURLConnection.setUseCaches(false);
            // 设置此 HttpURLConnection 实例是否应该自动执行 HTTP 重定向
            httpURLConnection.setInstanceFollowRedirects(true);
            // 设置连接超时时间
            httpURLConnection.setConnectTimeout(3000);
            // 设置读取返回超时时间
            httpURLConnection.setReadTimeout(3000);
            // 连接
            httpURLConnection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
            httpURLConnection.connect();
            // 4. 得到响应状态码的返回值 responseCode
            int code = httpURLConnection.getResponseCode();
            // 5. 如果返回值正常，数据在网络中是以流的形式得到服务端返回的数据
            String msg = "";
            if (code == 200) { // 正常响应
                log.info("正常响应200码：" +  msg);
                // 从流中读取响应信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8"));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循环从流中读取
                    msg += line;
                }
                reader.close(); // 关闭流
                // 显示响应结果
                log.info("请求返回：" +  msg);
                return msg;
            }else{
                // 显示响应结果
                log.info("异常响应码" + code + "：" +  msg);
                // 从流中读取响应信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8"));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循环从流中读取
                    msg += line;
                }
                reader.close(); // 关闭流
                // 显示响应结果
                log.info("请求返回：" +  msg);
                return null;
            }
        } catch (Exception e) {
            log.error("请求出错，错误信息："+e.getMessage()+";");
            e.printStackTrace();
            throw e;
        }finally {
            // 6. 断开连接，释放资源
            if (null != httpURLConnection){
                try {
                    httpURLConnection.disconnect();
                }catch (Exception e){
                    log.info("httpURLConnection 流关闭异常："+ e.getLocalizedMessage());
                    e.printStackTrace();
                    throw e;
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        SslUtil.createSSLContext("PKCS12","D:\\tomcat.p12","123456");
    }
}
